package indzcraft.calc;

public class Stats implements Cloneable {
	
	private static double BUFF_HORN_OF_WINTER = 549;
	private static double BUFF_MELEE_AP = 1.2;
	private static double BUFF_MOTW_MULTIPLIER = 1.05;
	private static double BUFF_ALL_CRIT = 5; // 5%
	private static double DEBUFF_SPELL_CRIT = 5; // 5%
	
	private static double BUFF_AGI_FLASK = 300;
	private static double BUFF_AGI_FOOD = 90;
	private static double BUFF_LEATHER_SPECIALIZATION = 1.05;
	
	private static double BUFF_COMBAT_VITALITY_AP = 1.3;
	private static double BUFF_SUBTLETY_SINISTER_CALLING_AGI = 1.3;
	
	Talents talents = null;
	
	double str = 0;
	double agi = 0;
	double ap = 0;
	double crit = 0;
	double hit = 0;
	double haste = 0;
	double exp = 0;
	double mastery = 0;
	
	double procs_agi = 0.;
	double procs_ap = 0.;
	double procs_haste = 0.;
	
	double t12_4pc_multiplier = 0.;
	
	// globals
	String ep = "";
	
	public Stats(int str, int agi, int ap, int crit, int hit, int haste, int exp, int mastery,Talents talents) {
		this.str = str;
		this.agi = agi;
		this.ap = ap;
		this.crit = crit;
		this.hit = hit;
		this.haste = haste;
		this.exp = exp;
		this.mastery = mastery;
		this.talents = talents;
	}
	
	public double get_str()
	{
		double base = this.str;
		base += BUFF_HORN_OF_WINTER; // horn of winter
		return base * BUFF_MOTW_MULTIPLIER;
	}
	
	public double get_agi()
	{
		double base = this.agi;
		base += BUFF_HORN_OF_WINTER; // horn of winter
		base += BUFF_AGI_FLASK; // flask
		base += BUFF_AGI_FOOD;  // agi food
		base += procs_agi; // Trinket, Weapon Procs...
		if(this.talents.isSubtlety())
			base *= BUFF_SUBTLETY_SINISTER_CALLING_AGI;
		return base * BUFF_MOTW_MULTIPLIER * BUFF_LEATHER_SPECIALIZATION;
	}
	
	public double get_ap()
	{
		double base = this.get_str() + this.get_agi() * 2 + this.ap;
		base += procs_ap; // Trinket, Weapon Procs...
		if(this.talents.isCombat())
			base *= (1 + 0.03*this.talents.get("savage_combat")) * BUFF_COMBAT_VITALITY_AP;
		return base * BUFF_MELEE_AP;
	}
	
	/*public double get_hit_chance()
	{
		double hit_misschance = Math.max(27-2*3-this.get_hit_by_conversion(), 0);
		double dodge_chance = Math.max(6.5-0.25*get_exp_by_conversion(), 0);
		if (this.ep.equals("white_hit") || this.ep.equals("spell_hit") || this.ep.equals("style_hit"))
			hit_misschance += 1 / 120.1094;
		if (this.ep.equals("exp"))
			dodge_chance += 0.25 * 1 / 30.0272;
		return 1 - 0.01*(hit_misschance+dodge_chance);
	}*/
	
	public double get_mh_hit_chance(Race race,Weapon mh)
	{
		double hit_misschance = Math.max(27-2*this.talents.get("precision")-this.get_hit_by_conversion(), 0);
		double dodge_chance = 6.5;
		if((race.get().equals("human") || race.get().equals("dwarf")) && mh.type.equals("mace")){
			dodge_chance -= 0.25*3;
		}
		else if(race.get().equals("human") && mh.type.equals("sword")){
			dodge_chance -= 0.25*3;
		}
		else if(race.get().equals("gnome") && mh.type.equals("dagger")){
			dodge_chance -= 0.25*3;
		}
		dodge_chance = Math.max(dodge_chance-0.25*get_exp_by_conversion(), 0);
		if (this.ep.equals("white_hit") || this.ep.equals("spell_hit") || this.ep.equals("style_hit"))
			hit_misschance += 1 / 120.1094;
		if (this.ep.equals("exp") || this.ep.equals("exp_mh"))
			dodge_chance += 0.25 * 1 / 30.0272;
		return 1 - 0.01*(hit_misschance+dodge_chance);
	}
	
	public double get_oh_hit_chance(Race race,Weapon oh)
	{
		double hit_misschance = Math.max(27-2*this.talents.get("precision")-this.get_hit_by_conversion(), 0);
		double dodge_chance = 6.5;
		if((race.get().equals("human") || race.get().equals("dwarf")) && oh.type.equals("mace")){
			dodge_chance -= 0.25*3;
		}
		else if(race.get().equals("human") && oh.type.equals("sword")){
			dodge_chance -= 0.25*3;
		}
		else if(race.get().equals("gnome") && oh.type.equals("dagger")){
			dodge_chance -= 0.25*3;
		}
		dodge_chance = Math.max(dodge_chance-0.25*get_exp_by_conversion(), 0);
		if (this.ep.equals("white_hit") || this.ep.equals("spell_hit") || this.ep.equals("style_hit"))
			hit_misschance += 1 / 120.1094;
		if (this.ep.equals("exp") || this.ep.equals("exp_oh"))
			dodge_chance += 0.25 * 1 / 30.0272;
		return 1 - 0.01*(hit_misschance+dodge_chance);
	}
	
	public double get_spell_hit_chance()
	{
		double spellhit_misschance = Math.max(17-2*this.talents.get("precision")-this.get_spell_hit_by_conversion(), 0);
		if (this.ep.equals("spell_hit") || this.ep.equals("style_hit"))
			spellhit_misschance += 1 / 102.446;
		return 1 - 0.01*spellhit_misschance;
	}
	
	public double get_style_hit_chance(Race race,Weapon mh)
	{
		double stylehit_misschance = Math.max(8-2*this.talents.get("precision")-this.get_hit_by_conversion(), 0);
		double dodge_chance = 6.5;
		if((race.get().equals("human") || race.get().equals("dwarf")) && mh.type.equals("mace")){
			dodge_chance -= 0.25*3;
		}
		else if(race.get().equals("human") && mh.type.equals("sword")){
			dodge_chance -= 0.25*3;
		}
		dodge_chance = Math.max(dodge_chance-0.25*get_exp_by_conversion(), 0);
		if (this.ep.equals("style_hit"))
			stylehit_misschance += 1 / 120.1094;
		if (this.ep.equals("exp") || this.ep.equals("exp_mh"))
			dodge_chance += 0.25 * 1 / 30.0272;
		return 1 - 0.01*(stylehit_misschance+dodge_chance);
	}
	
	public double get_crit_chance()
	{
		double RATING_AGI_TO_CRIT = 324.72;
		double crit_buffs = BUFF_ALL_CRIT;
		double crit_reduction = -4.8;
		double agi_crit_depression = -0.295;
		double agi_crit = this.get_agi()/RATING_AGI_TO_CRIT+agi_crit_depression;
		return (this.get_crit_by_conversion()+crit_buffs+crit_reduction+agi_crit)/100;
	}
	
	public double get_spell_crit_chance()
	{
		double spell_crit_buffs = BUFF_ALL_CRIT + DEBUFF_SPELL_CRIT;
		double spell_crit_reduction = -2.1;
		return (this.get_crit_by_conversion()+spell_crit_buffs+spell_crit_reduction)/100;
	}
	
	public double get_haste_by_conversion()
	{
		double base = this.haste;
		base += procs_haste; // Trinket, Weapon Procs...
		base *= (1+t12_4pc_multiplier);
		return base / 128.05701;
	}
	
	public double get_mastery_by_conversion()
	{
		double base = this.mastery;
		base *= (1+t12_4pc_multiplier);
		return 8 + base / 179.28;
	}
	
	public double get_hit_by_conversion()
	{
		return this.hit / 120.1094;
	}
	
	public double get_spell_hit_by_conversion()
	{
		return this.hit / 102.446;
	}
	
	public double get_crit_by_conversion()
	{
		double base = this.crit;
		base *= (1+t12_4pc_multiplier);
		return base / 179.28;
	}
	
	public double get_exp_by_conversion()
	{
		return this.exp / 30.0272;
	}
	
	public double get_eff_dmg()
	{
		double boss_armor = 11977*0.88;
		double param = 85 * 2167.5 - 158167.5;
		return param / (boss_armor + param);
	}
	
	public double get_eff_dmg(double armor)
	{
		double boss_armor = armor*0.88;
		double param = 85 * 2167.5 - 158167.5;
		return param / (boss_armor + param);
	}
	
	public Stats clone()
	{
		Object theClone = null;
		try {
			theClone = super.clone();
		}
		catch(CloneNotSupportedException e) {}
		
		return (Stats)theClone;
	}
}
